#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE 512
#define SEP " "
#define None_Redir 0
#define In_Redir 1
#define Out_Redir 2
#define Append_Redir 3

char* gArgv[SIZE];
char cwd[SIZE];
int redir = None_Redir;
const char* filename = NULL;
void Die(){
  ;
}
#define SkipCwd(path) do{path+=(strlen(path)-1);while(*path != '/')path--;path++;}while(0)
#define SkipSpace(cmd,pos) do{while(cmd[pos] == ' '|| cmd[pos] == '\0') {pos++;} }while(0)
//获取用户名
const char* getUsr(){
  const char* user = getenv("USER");
  if(user == NULL)return "None";
  return user;
}
//获取主机地址
const char* getHostname(){
  const char* hostname = getenv("HOSTNAME");
  if(hostname == NULL)return "None";
  return hostname;
}
//获取当前路径
const char*getCwd(){
  const char* cwd = getenv("PWD");
  if(cwd == NULL)return "None";
  return cwd;
}
void MakeCommandLineAndPrint(){
  const char* user = getUsr();
  const char* hostname = getHostname();
  const char* cwd = getCwd();
  SkipCwd(cwd);
  printf("[%s@%s %s]@",user,hostname,strlen(cwd) == 1? "/":cwd);
}


void GetCommand(char*command,size_t size){
  fgets(command,size,stdin);
  command[strlen(command)-1] = '\0';
}

void CheckRedir(char cmd[],size_t size){
  size_t pos = 0;
  size_t end = strlen(cmd);

  while(pos < end){
    //输入重定向
    if(cmd[pos] == '<'){
        cmd[pos++] = '\0';
        redir = In_Redir;
        SkipSpace(cmd,pos);
        filename = cmd + pos;
        break;
    }
    
    else if(cmd[pos] == '>'){
      cmd[pos++] = '\0';
      //追加重定向
      if(cmd[pos] == '>'){
            cmd[pos++] = '\0';
            redir = Append_Redir;
      }
      //输出重定向
      else 
            redir = Out_Redir;
      SkipSpace(cmd,pos);
      filename = cmd + pos;
      break;
    }
    else 
      pos++;
  }
}

void ModifyRedir(){
  if(redir == None_Redir)
    return;

    if(redir == In_Redir){
      close(0);
      int fd = open(filename,O_RDONLY | O_CREAT,0666);
      dup2(fd,0);
    }
    else if(redir == Out_Redir){
      close(1);
      int fd = open(filename,O_WRONLY | O_CREAT | O_TRUNC,0666);
      dup2(fd,1);
    }
    else if(redir == Append_Redir){
      close(1);
      int fd = open(filename,O_WRONLY | O_APPEND | O_CREAT,0666);
      dup2(fd,1);
    }
}

void SplitCommand(char command[],size_t size){
  gArgv[0] = strtok(command,SEP);
  int index = 1;
  (void)size;
  while((gArgv[index++] = strtok(NULL,SEP)));
}

//void chdir(){
//  pid_t id = fork();
//  if(id == 0){
//    execlp("cd",gArgv[1],NULL);
//    exit(errno);
//  }
//  else{
//    int status;
//    pid_t rid = waitpid(0,&status,0);
//    nux怎么在vim中选中所有并(void)status;
//
//  }
//} 
void Cd(){
  //用命令参数执行cd修改路径
  const char* path = gArgv[1];
  if(path == NULL) path = getenv("HOME");
  chdir(path);//执行cd
  char *gArgv[SIZE];

  //刷新环境变量
  char temp[SIZE];
  getcwd(temp,sizeof(temp));
  sprintf(cwd,"PWD=%s",temp);
  putenv(cwd); 
}
void Extern(){
  execvp("extern",gArgv+1);
}
void Echo(){
  execvp("echo",gArgv+1);
}
void Exit(){
  exit(0);
}


int CheckBuilt_inCommand(){
  if(strcmp(gArgv[0],"cd") == 0)
  {
    Cd();
    return 1;
  }
  else if (strcmp(gArgv[0],"extern") == 0)
  {
    Extern();
    return 1;
  }
  else if(strcmp(gArgv[0],"echo") == 0)
  {
    Echo();
    return 1;
  }
  else if(strcmp(gArgv[0],"exit") == 0)
  {
    Exit();
    return 1;
  }
  else return 0;
}

void ExcuteCommand(){
  pid_t id = fork();
  if(id < 0){
    Die();
  }
  else if(id == 0){
    ModifyRedir();
    execvp(gArgv[0],gArgv);
    exit(errno);
  }
  else{
    int status;
    pid_t rid = waitpid(0,&status,0);
    int lastcode = WEXITSTATUS(status);
    if(lastcode !=0 )
    {
      printf("%s:%s:%d\n",gArgv[0],strerror(lastcode),lastcode);
    }
  }
}


int main()
{
  while(1){
    redir = None_Redir;
    filename = NULL;

    //1.打印命令行
    MakeCommandLineAndPrint();

    //2.输入指令
    char command[SIZE];
    GetCommand(command,sizeof(command));

      //2.1判断重定向
      CheckRedir(command,sizeof(command));

      //2.2修改重定向
      //de-bug
      //printf("cmd:%s\n",command);
      //printf("redir:%d\n",redir);
      //printf("filename:%s\n",filename);
      //fflush(stdout);
      
    //3.分割指令字符串
    SplitCommand(command,sizeof(command));

    //4.检查是否是内建命令
    if(CheckBuilt_inCommand())
      continue;

    //n.执行命令
    ExcuteCommand();
  }


}
